package block

import (
	"encoding/hex"
	"encoding/json"
	"fmt"

	"bcb-cc-observ/pkg/consts"
	"bcb-cc-observ/pkg/models"
	"bcb-cc-observ/pkg/transaction"

	"github.com/golang/protobuf/proto"
	"github.com/hyperledger/fabric-protos-go/common"
	"github.com/hyperledger/fabric-sdk-go/pkg/client/ledger"
)

func GetBlockInfo(client *ledger.Client, blockNumber uint64) (*models.F_Block_Info, error) {
	var block *common.Block
	var blk *models.F_Block_Info
	blk = &models.F_Block_Info{}

	block, err := client.QueryBlock(blockNumber)
	if err != nil {
		return nil, err
	}

	b, err := json.Marshal(block)
	if err != nil {
		return nil, err
	}
	blk.BlockNumber = int(blockNumber)
	// block hash
	blockHash, err := blockHeaderHash(block.Header)
	if err != nil {
		blk.BlockHash = fmt.Sprintf("%v", err)
	} else {
		blk.BlockHash = hex.EncodeToString(blockHash)
	}
	blk.DataHash = hex.EncodeToString(block.Header.DataHash)
	blk.PreHash = hex.EncodeToString(block.Header.PreviousHash)
	blk.TxCount = len(block.Data.Data)
	blk.Size = len(b) / 1024

	// ---------- 解析交易信息 --------------
	n := blk.TxCount
	count := n
	for i := 0; i < count; i++ {
		// 单笔交易
		envelope, err := GetEnvelopeFromBlock(block.Data.Data[i])
		if err != nil {
			return nil, err
		}

		payload := &common.Payload{}
		err = proto.Unmarshal(envelope.Payload, payload)
		if err != nil {
			return nil, err
		}
		channelHeader := &common.ChannelHeader{}
		err = proto.Unmarshal(payload.Header.ChannelHeader, channelHeader)
		if err != nil {
			return nil, err
		}

		//0: "MESSAGE",
		//1: "CONFIG",
		//2: "CONFIG_UPDATE",
		//3: "ENDORSER_TRANSACTION",
		//4: "ORDERER_TRANSACTION",
		//5: "DELIVER_SEEK_INFO",
		//6: "CHAINCODE_PACKAGE",
		//8: "PEER_ADMIN_OPERATION",
		// type 1 配置交易 3 背书交易
		//g.Log().Infof("----> 交易类型: %v, %v", channelHeader.Type, common.HeaderType_name[channelHeader.Type])
		switch channelHeader.Type {
		case 1:
			txInfo, err := GetConfigInfo_ByPayload(channelHeader.ChannelId, payload)
			if err != nil {
				return nil, err
			}
			blk.Transactions = append(blk.Transactions, *txInfo)
			break
		case 3: // 背书交易
			// 根据txid查询交易
			txInfo, err := GetTxInfo_ByTxid(client, channelHeader.TxId)
			if err != nil {
				return nil, err
			}
			blk.Transactions = append(blk.Transactions, *txInfo)
			break
		default:
			sKey := consts.HeaderType_name[channelHeader.Type]
			sTmp := "not supported tx type"
			txInfo := models.F_Transaction_Info{
				TxId:   sKey,
				RWSets: sTmp,
			}
			blk.Transactions = append(blk.Transactions, txInfo)
			break
		}

	}

	return blk, nil
}

func GetConfigInfo_ByPayload(channelId string, payload *common.Payload) (*models.F_Transaction_Info, error) {
	// 配置交易，没有TxId
	configEnvelope, err := GetConfigEnvelopeFromPayload(payload.Data)
	if err != nil {
		return nil, err
	}
	sKey := fmt.Sprintf("%s_CONFIG", channelId)
	sTmp, err := GetConfigInfoJsonStr(configEnvelope)
	if err != nil {
		return nil, err
	}
	txInfo := models.F_Transaction_Info{
		TxId:       sKey,
		TypeStr:    "CONFIG",
		ChannelId:  channelId,
		CreatorMsp: "OrdererMSP",
		RWSets:     *sTmp,
	}

	return &txInfo, nil
}

func GetTxInfo_ByTxid(client *ledger.Client, txid string) (*models.F_Transaction_Info, error) {
	txInfo, err := transaction.GetTransactionInfo(client, txid)
	if err != nil {
		return nil, err
	}
	return txInfo, nil
}
